﻿#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>


//字符指针变量
//int main()
//{
//	char* pstr = "hello bit.";//这里是把首字符h的地址放在了pstr中
//	printf("%s\n", pstr);
//	printf("%p\n", pstr);
//
//	return 0;
//}
//int main()
//{
//	char str1[] = "hello bit.";//初始化数组，会开辟出一片内存储存
//	char str2[] = "hello bit.";//数组str1[]和数组str2[]开辟出的储存字符的空间不同，地址不同
//	const char* str3 = "hello bit.";//指针指向字符串
//	const char* str4 = "hello bit.";//指针str3和str4指向同一串字符串，也是同一片内存或者说地址
//	if (str1 == str2)//str[]储存字符,str表示字符串地址
//		printf("str1 and str2 are same\n");
//	else
//		printf("str1 and str2 are not same\n");
//
//	if (str3 == str4)
//		printf("str3 and str4 are same\n");
//	else
//		printf("str3 and str4 are not same\n");
//
//	return 0;
//}
//这⾥str3和str4指向的是同⼀个常量字符串。C / C++会把常量字符串存储到单独的⼀个内存区域，
//当⼏个指针指向同⼀个字符串的时候，他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始
//化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同，str3和str4相同。





//数组指针
//简单对比
//int main()
//{
//	int a = 0;
//	int* pa = &a;//pa存a的地址
//
//	int arr1[10] = { 0 };
//	int* p1 = arr1;//p1存arr1中首元素(arr[0])的地址
//
//	int arr2[10] = { 0 };
//	int(*p2)[5] = &arr2;
//	//数组指针,p2存放的为数组arr2的地址
//	printf("p2   =%p\n", p2);
//	printf("&arr2=%p\n", &arr2);
//	//p2与&arr2所存储的地址是一样的
//
//	int* arr3[10] = { 0,1,2,3,4,5,6,7,8,9 };
//	//指针数组，数组中存放的是指针
//	//arr3[0]表示0(数组中对应的元素)的地址,同理arr3[n]存*arr3[n]的地址
//	//如果数组中元素为数组，则表示数组的首元素的地址
//	int i = 0;								
//	for (i = 0; i < 10; i++)
//	{
//		printf("&arr3[%d]=%p\n", i, arr3[i]);
//	}
//
//	return 0;
//}
//深入剖析
//int main()
//{
//	int i = 0;
//
//	int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };
//	int* p1 = arr1;
//	printf("%p\n", &arr1);
//	printf("%p\n", p1);
//	printf("%p\n", p1 + 1);//相比于p1地址增加了4个字节(1个int*)
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", *(p1 + i));
//	}
//	printf("\n");
//
//	int arr2[10] = { 0,1,2,3,4,5,6,7,8,9 };
//	int(*p2)[10] = &arr2;//[10]代表储存(指向)的数组中元素的个数
//	printf("%p\n", &arr2);
//	printf("%p\n", p2);
//	printf("%p\n", p2 + 1);//相比于p2地址增加了20个字节(5个int*)
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", (*p2)[i]);//*p2==arr2,先这样方便理解
//	}
//	printf("\n");
//
//	return 0;
//}




//二维数组传参的本质
//void test(int arr[3][4], int a, int b)
//{
//	int i, j;
//	for (i = 0; i < a; i++)
//	{
//		for (j = 0; j < b; j++)
//		{
//			printf("%-3d ", arr[i][j]);
//		}
//		printf("\n");
//	}
//}
//void test(int(*p)[4], int a, int b)
//{
//	int i, j;
//	for (i = 0; i < a; i++)
//	{
//		for (j = 0; j < b; j++)
//		{
//			printf("%-3d ", *(*(p + i) + j));
//			//int(*p)[4]=&arr
//			//p+i指向arr中i行的数组
//			//*(p+i)+j指向i行j列元素
//		}
//		printf("\n");
//	}
//}
//int main()
//{
//	int arr[3][4] = { {0,1,2,3},{10,11,12,13},{0} };
//	test(arr, 3, 4);
//	return 0;
//}




//函数指针变量的创建与调用
//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int(*pf)(int, int) = Add;//这里int后有没有形参都可以，Add与&Add
//
//	printf("%p\n", pf);
//	printf("%p\n", &Add);
//	printf("%p\n", Add);//这仨地址一样
//
//	int a = Add(1, 2);//函数名调用
//	printf("%d ", a);//结果为3
//
//	int b = (*pf)(1, 2);//函数指针调用
//	printf("%d ", b);//结果为3
//
//	int c = pf(1, 2);//函数指针调用
//	printf("%d ", c);//结果为3
//	//三个结果一样
//
//	return 0;
//}



//？？？

//(*(void(*)())0)();
//void(*)()--函数指针类型(类比void型)
//(void(*)())0--将0强制转换为void(*)()函数指针类型(类比int型强制转换成void型)，到这一步主体为void(*)()函数指针类型的0(形象上是0)
//可以吧void(*)()函数指针类型的0类比为*pf，即*pf()
//意思就是调用void(*)()函数指针类型的0所指向的函数

//void(*signal(int, void(*)(int)))(int);//这是一个函数声明，当然下面加个{}再加一些内容就成定义函数指针了
////sigenal--函数
////int--整型,参数1
////void(*)(int)--函数指针类型,参数2
//将以上看做一个整体剩下void(*)(int)，也即signal函数的返回类型为void(*)(int)
//总的类比
//void(*p)(int);//函数声明，将p换成signal函数即可
//(*p)(10);//对p所指向的函数的使用



////typedef关键字
//typedef unsigned int uint;
////将unsigned int 命名为 uint
//typedef int* ptr_t;
////将int* 命名为 ptr_t
//typedef int(*parr_t)[5];
////将int(*)[5] 命名为parr_t
//int main()
//{
//	unsigned int a1;
//	uint a2;
//
//	int* b1;
//	ptr_t b2;
//
//	int(*c1)[5];
//	parr_t c2;//原类型与重定义类型之间用法的差异
//
//	return 0;
//}



//函数指针数组,与指针数组的差别也就是数组中储存的是函数的指针
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
void menu()
{
	printf("*********************\n");
	printf("****    0.exit   ****\n");
	printf("****1.Add   2.Sub****\n");
	printf("****3.Mul   4.Div****\n");
	printf("*********************\n");
}
int main()
{
	int(*pfarr[5])(int, int) = { 0,Add,Sub,Mul,Div };//对于传参相同的函数可以将他们放在同一个函数指针数组当中
	//pafarr[5]就是一个函数指针数组
	int input = 0;
	int a = 0;
	int b = 0;
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入要进行运算的两个整数\n");
			scanf("%d %d", &a, &b);
			int c = (*pfarr[input])(a, b);
			printf("运算结果为:>%d\n\n\n", c);
		}
		else if (input == 0)
		{
			printf("退出计算机\n");
			break;
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	} while (input);
	return 0;
}